package main

import (
	"cqTcp/do"
	"cqTcp/logger"
	"cqTcp/settings"
	"encoding/base64"
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/spf13/viper"
	"go.uber.org/zap"
)

/*
*
连接失败按固定时长重连
*/
func dialTCPWithRetry(network string, address string, timeout time.Duration) (net.Conn, error) {
	var conn net.Conn
	var err error
	for {
		conn, err = net.DialTimeout(network, address, timeout)
		if err == nil {
			break
		}
		fmt.Println("Try connecting to the server again")
		zap.L().Debug("connect fail", zap.String("address", address), zap.Error(err))
		time.Sleep(timeout)
	}
	return conn, err
}

func main() {
	var conn net.Conn
	var err error
	if len(os.Args) < 2 {
		fmt.Println("need config file.eg: xxx config.yaml")
		return
	}

	// 1.加载配置
	if err := settings.Init(os.Args[1]); err != nil {
		fmt.Printf("Init settings failed, err:%v\n", err)
		return
	}
	// 2.初始化日志
	if err := logger.Init(settings.Conf.LogConfig); err != nil {
		fmt.Printf("Init logger failed, err:%v\n", err)
		return
	}
	defer zap.L().Sync()
	zap.L().Debug("logger init success...")

	for {
		// 3.连接TCP服务
		conn, err = dialTCPWithRetry(viper.GetString("app.type"), fmt.Sprintf("%s:%d", viper.GetString("app.addr"), viper.GetInt("app.port")), 5*time.Second)
		if err != nil {
			zap.L().Fatal("Error connecting to server:", zap.Error(err))
			return
		}

		go func() {
			defer func() {
				if a := recover(); a != nil {
					fmt.Println("Recover from panic:", a)
				}
			}()
			do.ListenCodeFile(conn, settings.Conf.FilePathConfig)
		}()

		go func() {
			defer func(conn net.Conn) {
				err := conn.Close()
				if err != nil {
					zap.L().Fatal("Error closing connection:", zap.Error(err))
				}
				os.Exit(1)
			}(conn)
			quit := make(chan os.Signal, 1)
			signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
			<-quit
			zap.L().Info("Shutdown Server ...")
		}()

		go func() {
			for {
				buf := make([]byte, 512)
				n, err := conn.Read(buf)
				if err != nil {
					zap.L().Info(fmt.Sprintf("server closed:%s", err))
					break
				}
				zap.L().Info(fmt.Sprintf("Received from server:%s", string(buf[0:n])))
			}
		}()

		for {
			base64Str := base64.StdEncoding.EncodeToString([]byte("ping"))
			_, err := conn.Write([]byte(base64Str))
			if err != nil {
				break
			}
			time.Sleep(10 * time.Second)
		}
	}
}
